
/**
 * IMAGE MANIPULATION OPCODES
 *
 * imagemanip.c
 *
 * Copyright (c) 2010 by Justin Glenn Smith <noisesmith@gmail.com>.
 * All rights reserved.
 *
 * L I C E N S E
 *
 * This software is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * C S O U N D   M A N   P A G E
 *
 * imageblit            - pastes a rectangle from one image into another
 * imagediv             - divides the pixels in a section of one image by a
 *                        section of another
 * SYNTAX
 *
 *              imageblit iImageIn, ix1, iy1, iw, ih, ix2, iy2, iImageOut
 *
 * there is no bounds checking, x/y/w/h variables are presumed to be in the
 * 0-1 range
 */

#include "imagemanip.h"

static int imageblit (CSOUND *csound, IMGBLIT * p)
{
  Images *imgs;
  Image *imgin;
  Image *imgout;
  int x, y, xoff1, yoff1, xoff2, yoff2, xlim, ylim;
  int pixelin, pixelout;

  imgs = (Images *) csound->QueryGlobalVariable(csound,
						 "imageOpcodes.images");
  imgin = imgs->images[(int)(*p->iin)-1];
  imgout = imgs->images[(int)(*p->iout)-1];

  xoff1 = (*p->ix1)*(imgin->w);
  yoff1 = (*p->iy1)*(imgin->h);
  xoff2 = (*p->ix2)*(imgout->w);
  yoff2 = (*p->iy2)*(imgout->h);
  xlim = (*p->iw)*(imgin->w);
  ylim = (*p->ih)*(imgin->h);
  x = 0;
  do {
    y = 0;
    do{
      pixelin = ((imgin->w)*(y+yoff1)+(x+xoff1))*3;
      pixelout = ((imgout->w)*(y+yoff2)+(x+xoff2))*3;
      imgout->imageData[ pixelout ] = imgin->imageData[ pixelin ];
      imgout->imageData[ pixelout+1 ] = imgin->imageData[ pixelin+1 ];
      imgout->imageData[ pixelout+2 ] = imgin->imageData[ pixelin+2 ];
      y++;
    } while((y<ylim) && (y+yoff1<imgin->h) && (y+yoff2<imgout->h));
    x++;
  } while((x<xlim) && (x+xoff1<imgin->w) && (x+xoff2<imgout->w));
  return OK;
}

static int imagediv (CSOUND *csound, IMGBLIT * p)
{
  Images *imgs;
  Image *imgin;
  Image *imgout;
  int x, y, xoff1, yoff1, xoff2, yoff2, xlim, ylim;
  int pixelin, pixelout;
  double r1, r2, g1, g2, b1, b2;

  imgs = (Images *) csound->QueryGlobalVariable(csound,
                                                 "imageOpcodes.images");
  imgin = imgs->images[(int)(*p->iin)-1];
  imgout = imgs->images[(int)(*p->iout)-1];

  xoff1 = (*p->ix1)*(imgin->w);
  yoff1 = (*p->iy1)*(imgin->h);
  xoff2 = (*p->ix2)*(imgout->w);
  yoff2 = (*p->iy2)*(imgout->h);
  xlim = (*p->iw)*(imgin->w);
  ylim = (*p->ih)*(imgin->h);

  x = 0;
  do {
    y = 0;
    do{
      pixelin = ((imgin->w)*(y+yoff1)+(x+xoff1))*3;
      pixelout = ((imgout->w)*(y+yoff2)+(x+xoff2))*3;
      r1 = (imgout->imageData[ pixelout ]+1)/255.0;
      r2 = (imgin->imageData[ pixelout ]+1)/255.0;
      r1 = r1/r2;
      imgout->imageData[ pixelout ] = r1 > 1 ? 255 : r1*255;
      g1 = (imgout->imageData[ pixelout+1 ]+1)/255.0;
      g2 = (imgin->imageData[ pixelout ]+1)/255.0;
      g1 = g1/g2;
      imgout->imageData[ pixelout+1 ] = g1 > 1 ? 255 : g1*255;
      b1 = (imgout->imageData[ pixelout+2 ]+1)/255.0;
      b2 = (imgin->imageData[ pixelout ]+1)/255.0;
      b1 = b1/b2;
      imgout->imageData[ pixelout+2 ] = b1 > 1 ? 255 : b1*255;
      y++;
    } while((y<ylim) && (y+yoff1<imgin->h) && (y+yoff2<imgout->h));
    x++;
  } while((x<xlim) && (x+xoff1<imgin->w) && (x+xoff2<imgout->w));
  return OK;
}


static int imagegain (CSOUND *csound, IMGGAIN * p)
{
  Images *imgs;
  Image *img;
  int x, y;
  int subpixel, newcolor;

  imgs = (Images *) csound->QueryGlobalVariable(csound, "imageOpcodes.images");
  img = imgs->images[(int)(*p->iim)-1];

  for(y = 0; y < img->w; y++) {
    for(x = 0; x < img->h; x++) {
      subpixel = ((y*img->w)+x)*3;
      newcolor = img->imageData[ subpixel ] * *p->irg;
      img->imageData[ subpixel ] = newcolor;
      subpixel++;
      newcolor = img->imageData[ subpixel ] * *p->igg;
      img->imageData[ subpixel ] = newcolor;
      subpixel++;
      newcolor = img->imageData[ subpixel ] * *p->ibg;
      img->imageData[ subpixel ] = newcolor;
    }
  }
  return OK;
}

static int imagepaint (CSOUND *csound, IMGPAINT * p)
{
  Images *imgs;
  Image *img;
  int x, y;
  int subpixel;
  int xoffset, xmax, yoffset, ymax;

  imgs = (Images *) csound->QueryGlobalVariable(csound, "imageOpcodes.images");
  img = imgs->images[(int)(*p->kim)-1];

  xoffset = (int) (img->w * *p->kx);
  //  xoffset = (xoffset < img->w) ? xoffset : img->w;
  xmax = (int) (img->w * *p->kw) + xoffset;
  //  xmax = (xoffset+xmax < img->w) ? xmax : img->w - xoffset;
  yoffset = (int) (img->h * *p->ky);
  //  yoffset = (yoffset < img->h) ? yoffset : img->h;
  ymax = (int) (img->h * *p->kh) + yoffset;
  //  ymax = (yoffset+ymax < img->h) ? ymax : img->h - yoffset;

  for(x = xoffset; x < xmax; x++) {
    for(y = yoffset; y < ymax; y++) {
      subpixel = ((y * img->w) + x)*3;
      img->imageData[ subpixel ] = *p->kr * 255.0;
      subpixel++;
      img->imageData[ subpixel ] = *p->kg * 255.0;
      subpixel++;
      img->imageData[ subpixel ] = *p->kb * 255.0;
    }
  }
  return OK;
}

static OENTRY localops[] = {
  { "imageblit",  sizeof(IMGBLIT),  1, "", "iiiiiiii", (SUBR)imageblit,
    NULL, NULL },
  { "imagediv",  sizeof(IMGBLIT),  1, "", "iiiiiiii", (SUBR)imagediv,
    NULL, NULL },
  { "imagegain", sizeof(IMGGAIN), 1, "", "iiii", (SUBR)imagegain, NULL, NULL },
  { "imagepaint", sizeof(IMGPAINT), 2, "", "kkkkkkkk", NULL,
    (SUBR)imagepaint, NULL },
};

LINKAGE
